﻿using System;
using System.Windows;
using System.Windows.Documents;
using Notoric.Commanding.CommandBase;

namespace Notoric.ViewModel
{
    /// <summary>
    /// Implements an undoable command for setting a formating property on a text selection.
    /// </summary>
    /// <remarks>
    /// Input Parameters:
    /// <list type="table">
    /// <listheader>
    /// <term>
    ///     Name
    /// </term>
    /// <description>
    ///     Description
    /// </description>
    /// </listheader>
    /// <item>
    /// <term>
    ///     <see cref="Property"/> (<see cref="DependencyProperty"/>)
    /// </term>
    /// <description>
    ///     The formating property that will be modified by the command.
    /// </description>
    /// </item>
    /// <item>
    /// <term>
    ///     <see cref="Selection"/> (<see cref="TextSelection"/>)
    /// </term>
    /// <description>
    ///     The text selection that will be modified by the command.
    /// </description>
    /// </item>
    /// <item>
    /// <term>
    ///     <see cref="Value"/> (<see cref="object"/>)
    /// </term>
    /// <description>
    ///     The value that the command will apply to the <see cref="Property"/> of <see cref="Selection"/>.
    /// </description>
    /// </item>
    /// </list>
    /// </remarks>
    public class SetFormatPropertyCommand : UndoableCommandBase
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="SetFormatPropertyCommand"/> class.
        /// </summary>
        /// <param name="undoStack">The undo stack</param>
        /// <param name="redoStack">The redo stack</param>
        public SetFormatPropertyCommand(CommandStack undoStack, CommandStack redoStack)
            : base(undoStack, redoStack)
        {
            AddParameter<DependencyProperty>("Property", ParameterDirection.In);
            AddParameter<TextSelection>("Selection", ParameterDirection.In);
            AddParameter<object>("Value", ParameterDirection.In);
        }

        #endregion

        #region Command Logic

        /// <inheritdoc/>
        protected override void CommandOperation(object parameter)
        {
            oldValue = Selection.GetPropertyValue(Property);
            Selection.ApplyPropertyValue(Property, Value);
        }

        /// <inheritdoc/>
        protected override void RedoOperation()
        {
            Selection.ApplyPropertyValue(Property, Value);
        }

        /// <inheritdoc/>
        protected override void UndoOperation()
        {
            Selection.ApplyPropertyValue(Property, oldValue);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the formating property that is being set by this command.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="DependencyProperty"/>
        /// </para>
        /// <para>
        /// The formating property that is being set by this command.<br/>
        /// This property wraps the "Property" command parameter.
        /// </para>
        /// </value>
        public DependencyProperty Property
        {
            get { return GetParameterValue<DependencyProperty>("Property"); }
            set { SetParameterValue<DependencyProperty>("Property", value); }
        }

        /// <summary>
        /// Gets or sets the text selection modified by this command.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="TextSelection"/>
        /// </para>
        /// <para>
        /// The text selection modofied by this command.<br/>
        /// This property wraps the "Selection" command parameter.
        /// </para>
        /// </value>
        public TextSelection Selection
        {
            get { return GetParameterValue<TextSelection>("Selection"); }
            set { SetParameterValue<TextSelection>("Selection", value); }
        }

        /// <summary>
        /// Gets or sets the value set by this command.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Object"/>
        /// </para>
        /// <para>
        /// The value that this command sets to the <see cref="Property"/>.<br/>
        /// This property wraps the "Value" command parameter.
        /// </para>
        /// </value>
        public object Value
        {
            get { return GetParameterValue<object>("Value"); }
            set { SetParameterValue<object>("Value", value); }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the old <see cref="Property"/> value.
        /// </summary>
        private object oldValue;

        #endregion
    }
}
